package com.rightsidetech.http.aspect;


import com.alibaba.dubbo.rpc.RpcException;
import com.rightsidetech.commom.base.ResponseData;
import com.rightsidetech.commom.enums.CodeIdEnum;
import com.rightsidetech.commom.exception.BizException;
import com.rightsidetech.commom.exception.ParaException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.multipart.MaxUploadSizeExceededException;
import org.springframework.web.multipart.MultipartException;
import org.springframework.web.servlet.NoHandlerFoundException;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolationException;
import java.lang.reflect.UndeclaredThrowableException;
import java.net.SocketTimeoutException;

/**
 * @Description: controller异常处理切面
 */
@RestControllerAdvice
public class ControllerExceptionHandlerAdvice {

    private static final Logger logger = LoggerFactory.getLogger(ControllerExceptionHandlerAdvice.class);

    @ExceptionHandler(Exception.class)
    public ResponseData<Object> handleException(HttpServletRequest request, Exception e) throws Exception {

        // 如果是feign调用，则抛出异常
        String txGroup = request.getHeader("tx-group");
        if (txGroup != null) {
            throw e;
        }

        String error = "[%s] [%s]";
        String uri = request.getRequestURI();
        String errorMessage = null;
        CodeIdEnum erorCodeEnum = null;

        if (e instanceof UndeclaredThrowableException) {
            Throwable targetEx = ((UndeclaredThrowableException) e).getUndeclaredThrowable();
            if (targetEx != null) {
                if (targetEx instanceof BizException){
                    BizException te = (BizException) targetEx;
                    erorCodeEnum = te.getErrorCodeEnum();
                    errorMessage = te.getMessage();
                }
                else if (targetEx instanceof ParaException){
                    ParaException te = (ParaException) targetEx;
                    errorMessage = te.getMessage();
                }else {
                    targetEx.printStackTrace();
                    errorMessage = targetEx.getMessage();
                }
            }
        }

        else if (e instanceof BizException) {
            BizException targetEx = (BizException) e;
            erorCodeEnum = targetEx.getErrorCodeEnum();
            errorMessage = targetEx.getMessage();
        }

        else if (e instanceof ParaException) {
            ParaException targetEx = (ParaException) e;
            errorMessage = targetEx.getMessage();
        }
        else if (e instanceof MissingServletRequestParameterException) {
            MissingServletRequestParameterException targetEx = (MissingServletRequestParameterException) e;
            errorMessage = targetEx.getMessage();
            erorCodeEnum = CodeIdEnum.AnalysisError ;
        }
        else if (e instanceof MaxUploadSizeExceededException) {
            MaxUploadSizeExceededException targetEx = (MaxUploadSizeExceededException) e;
            errorMessage = targetEx.getMessage();
            erorCodeEnum = CodeIdEnum.MAX_UPLOAD_SIZE ;
        }
        else if (e instanceof ClassCastException) {
            ClassCastException targetEx = (ClassCastException) e;
            errorMessage = targetEx.getMessage();
            erorCodeEnum = CodeIdEnum.ParameterMalformed ;
        }
        else if (e instanceof org.springframework.validation.BindException
                || e instanceof HttpMessageNotReadableException || e instanceof MethodArgumentTypeMismatchException) {
            erorCodeEnum = CodeIdEnum.IllegalParameter ;
        }
        else if (e instanceof NoHandlerFoundException) {
            NoHandlerFoundException targetEx = (NoHandlerFoundException) e;
            errorMessage = targetEx.getMessage();
        }
        //参数校验这块的异常
        else if (e instanceof MethodArgumentNotValidException) {
            MethodArgumentNotValidException manvExceptionex = (MethodArgumentNotValidException) e;
            errorMessage = "@Validated约束在参数模型前，校验该模型的字段时发生异常 -> " + manvExceptionex.getMessage();
        }
        else if (e instanceof ConstraintViolationException) {
            ConstraintViolationException cvExceptionex = (ConstraintViolationException) e;
            errorMessage = "@Validated约束在类上，直接校验接口的参数时异常 -> " + cvExceptionex.getMessage();
            //请求超时
        } else if (e instanceof SocketTimeoutException || e instanceof RpcException) {
            errorMessage = "发送请求超时，请联系管理员。";
            logger.error(e.getMessage());
        } else if (e instanceof MultipartException) {
            MultipartException targetEx = (MultipartException) e;
            errorMessage = targetEx.getMessage();
            erorCodeEnum = CodeIdEnum.FILE_UPLOAD_EXEPECTION;
        } else {
            e.printStackTrace();
            erorCodeEnum = CodeIdEnum.ServerError;
        }

        error = String.format(error, uri, errorMessage);
        logger.error(error,e);
        if (erorCodeEnum != null) {
            return ResponseData.fail(erorCodeEnum);
        } else {
            return ResponseData.fail(errorMessage);
        }
    }

}

